package cn.dengta.webapp.trade.service;

import java.math.BigDecimal;
import java.util.*;
import javax.annotation.*;

import cn.dengta.common.model.Bean;
import cn.dengta.common.model.Messager;
import cn.dengta.common.util.SpringUtil;
import cn.dengta.context.model.MessagerStatus;
import cn.dengta.context.web.RequestContextImpl;
import cn.dengta.webapp.base.entity.BaseEntity;
import cn.dengta.webapp.trade.dao.UserGoldDao;
import cn.dengta.webapp.trade.dto.UserGoldTradeDTO;
import cn.dengta.webapp.trade.entity.UserGold;
import cn.dengta.webapp.trade.entity.UserGoldLog;
import cn.dengta.webapp.trade.model.*;
import cn.dengta.webapp.user.entity.User;
import cn.dengta.webapp.user.entity.userLevel.UserLevelRule;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 用户金币账户 服务实现类
 *
 * @author Ready
 * @since 2022-11-21
 */
@Service
@Transactional
public class UserGoldService {

	@Resource
	UserGoldDao userGoldDao;
	@Resource
	UserGoldLogService userGoldLogService;
	@Resource
	UserLevelService userLevelService;

	public UserGold getUserIdForUpdate(Long userId) {
		UserGold gold = new UserGold();
		gold.setUserId(userId);
		QueryWrapper<UserGold> query = new QueryWrapper<>(gold);
		query.last("FOR UPDATE");
		return userGoldDao.selectOne(query);
	}

	public UserGold get(Long id) {
		return userGoldDao.selectById(id);
	}

	public int save(UserGold gold) {
		Date now = RequestContextImpl.get().now();
		gold.setAddTime(now);
		gold.setUpdateTime(now);
		return userGoldDao.insert(gold);
	}

	public int updateById(UserGold gold) {
		return userGoldDao.updateById(gold);
	}

	public List<UserGold> findByIds(Long... ids) {
		return userGoldDao.selectBatchIds(Arrays.asList(ids));
	}

	/**
	 * 金币交易
	 */
	public Messager<UserGoldTradeDTO> trade(@Nonnull Long userId, @Nonnull Integer amount, @Nonnull GoldTradeType tradeType, @Nullable BaseEntity obj, BigDecimal assocNum, String remark) {
		UserGold userGold = getUserIdForUpdate(userId);
		TradeTypeCore core = tradeType.getFrom();
		// 余额不足
		if (userGold == null || (core == TradeTypeCore.DEDUCT_ACTIVE && amount > userGold.getActiveAmount())) {
			return Messager.status(MessagerStatus.LESS_GOLD);
		}
		UserGoldLog log = UserGoldLog.init(userGold, tradeType, amount, obj);
		final Date now = RequestContextImpl.get().now();
		log.initTime(now);
		log.setAssocNum(assocNum);
		log.setRemark(remark);
		userGoldLogService.save(log);
		userGold.setUpdateTime(now);
		userGoldDao.updateById(userGold);
		if (Flow.CONSUME.eq(log.getFlow()) && amount >= 100) { // 每次消耗钻石超过100增加经验值
			SpringUtil.asyncRun(() -> userLevelService.change(UserLevelRule.UserLevelRuleType.USE_GOLD, null, log, Bean.of(User::new, userId), amount, now), "用户等级（消耗金币）");
		}
		return Messager.exposeData(new UserGoldTradeDTO(userGold, log));
	}

}
